# -*- coding: utf-8 -*-
# @Author: Jerry
# @Date:   2022-02-25 10:44:47
# @Last Modified by:   Jerry
# @Last Modified time: 2022-03-01 15:29:14

# **********
# **********
# OpenCV中的图像处理 » 4_9_4_轮廓：更多属性
# http://www.woshicver.com

# **********
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
import os
rootpath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
datapath = os.path.join(rootpath,'data')
imgpath = lambda name: os.path.join(datapath,name)

# **********
'''目标
本章将学习
- 凸性缺陷以及如何找到它们
- 查找点到多边形的最短距离
- 匹配不同的形状'''


# **********
'''1. 凸性缺陷
第二章介绍了轮廓的凸包，从这个凸包上的任何偏差都可以被认为是凸性缺陷。
OpenCV有一个函数来找到这个,cv.convexityDefects()

它返回一个数组，其中每行包含这些值—[起点、终点、最远点、到最远点的近似距离]。
返回的前三个值是cnt的索引. 所以我们必须从cnt中获取这些值。
'''
src = cv.imread(imgpath('star1.png'))
print 'src.shape =',src.shape
imggray = cv.cvtColor(src,cv.COLOR_BGR2GRAY)
ret,thresh = cv.threshold(imggray,127,255,0)
contours,hierarchy = cv.findContours(thresh,2,1)
cnt = contours[0]
# print  cnt
hull = cv.convexHull(cnt,returnPoints=False) # 我们必须在发现凸包时,传递returnPoints= False,以找到凸性缺陷。
defects = cv.convexityDefects(cnt,hull)
# 太多的属性值都是从 cnt这个数据库来的，这个参量中存储的内容庞大复杂
for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    print 'start =',start
    end = tuple(cnt[e][0])
    print 'end =',end
    far = tuple(cnt[f][0])
    print 'far =',far  #凸包缺陷距离最大的点的坐标
    cv.line(src,start,end,[0,255,0],2)
    cv.circle(src,far,5,[0,0,255],-1) # 画个圆点
cv.imshow('src',src)


# **********
'''2. 点多边形测试
cv.pointPolygonTest 这个函数找出图像中一点到轮廓线的最短距离。
它返回的距离，点在轮廓线外时为负，点在轮廓线内时为正，点在轮廓线上时为零。'''

# 检查点(50,50)与轮廓cnt的关系

dist = cv.pointPolygonTest(cnt,(50,50),True)
# 第三个参数是measureDist。
# 如果为True，它会找到有符号的距离。
# 如果为False，则查找该点是在轮廓线内部还是外部(分别返回+1、-1和0)。
#
# 如果您不想找到距离，请确保第三个参数为False，因为这是一个耗时的过程。
# 将其设置为False可使速度提高2-3倍。
print 'dist =',dist


# **********
'''3. 形状匹配
OpenCV附带一个函数 cv.matchShapes()，该函数使我们能够比较两个形状或两个轮廓，并返回一个显示相似性的度量。
结果越低，匹配越好。它是根据矩值计算出来的。不同的测量方法在文档中有解释。'''

img2 = cv.imread(imgpath('star2.png'))
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
ret2,thresh2 = cv.threshold(img2gray,127,255,0)
contours2,hierarchy2 = cv.findContours(thresh2,2,1)
cnt2 = contours2[0]
match_ret12 = cv.matchShapes(cnt,cnt2,1,0.0)
print 'match_ret12 =',match_ret12 #0.00158836640428，匹配度较好
# star2.png是图start1.png顺时针选择45度的图，
# 由此可知，通过cnt的比较，图像的旋转不会对这比较结果产生较大影响

img3 = cv.imread(imgpath('star3.png'))
img3gray = cv.cvtColor(img3,cv.COLOR_BGR2GRAY)
ret3,thresh3 = cv.threshold(img3gray,127,255,0)
contours3,hierarchy3 = cv.findContours(thresh3,2,1)
cnt3 = contours3[0]
match_ret13 = cv.matchShapes(cnt,cnt3,1,0.0)
print 'match_ret13 =',match_ret13 # 0.351536557677，匹配度较差

# Hu矩是平移、旋转和比例不变的七个矩。第七个是无偏斜量。
# 这些值可以使用 cpu.HuMoments() 函数找到。

cv.waitKey(0)

